from celery import shared_task
from celery.utils.log import get_task_logger
from django.core.cache import caches
from django.core.exceptions import ObjectDoesNotExist
import os

from .models import Exam, ExamDepart
from django.utils import timezone

from ..PaperManagement.models import PaperQuestion
from ..ResultManagement.models import Results, ResultQuestionSolution

# 设置环境变量
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'application.settings')
logger = get_task_logger('my_celery_logger')
current_tz = timezone.get_current_timezone()

@shared_task
def start_exam(exam_id):
    try:
        exam = Exam.objects.get(id=exam_id)
        start_time = exam.start_time
        start_time = start_time.astimezone(current_tz)
        if start_time <= timezone.now() and exam.status == 0:
            exam.status = 1
            exam.number += 1  # 考试结束时考试次数加一
            exam.save()
            logger.info(f"Exam {exam.title} started at {start_time}.")
    except ObjectDoesNotExist:
        logger.error(f"Exam {exam_id} does not exist.")

@shared_task
def end_exam(exam_id):
    try:
        exam = Exam.objects.get(id=exam_id)
        end_time = exam.end_time.astimezone(current_tz)
        if timezone.now() < end_time:
            # 如果当前时间还未到结束时间，延迟任务再次执行
            logger.warning(f"Task executed too early. Rescheduling end_exam for exam {exam.id}.")
            end_exam.apply_async((exam_id,), eta=end_time)
            return

        if end_time <= timezone.now() and exam.status == 1:
            exam.status = 2
            exam.save()
            results = Results.objects.filter(exam=exam)
            really_exam_users = [] # 实际参加考试的用户
            should_exam_users = [] # 应该参加考试的用户
            # 获取实际参加考试的用户
            if results:
                for result in results:
                    really_exam_users.append(result.user)
            # 获取应该参加考试的用户
            exam_depart_user = ExamDepart.objects.filter(exam=exam)
            if exam_depart_user:
                for depart_user in exam_depart_user:
                    # 获取部门下的所有用户
                    if depart_user.depart:
                        depart = depart_user.depart
                        users = depart.user.all()
                        if users:
                            for user in users:
                                should_exam_users.append(user)
                    # 获取补考用户
                    if depart_user.user:
                        user = depart_user.user
                        should_exam_users.append(user)
            should_exam_users = list(set(should_exam_users)) # 去重
            really_exam_users = list(set(really_exam_users))
            missed_exam_users = []
            for user in should_exam_users:
                if user not in really_exam_users:
                    # 未参加考试的用户
                    missed_exam_users.append(user)
            # 未参加考试的用户，成绩为0
            paper = exam.paper
            if missed_exam_users and paper:
                for user in missed_exam_users:
                    result = Results.objects.create(
                        exam=exam,
                        user=user,
                        total_score=0,
                    )
                    paper_questions = PaperQuestion.objects.filter(paper=paper)
                    for paper_question in paper_questions:
                        question = paper_question.question
                        ResultQuestionSolution.objects.create(
                            results=result,
                            question=question,
                            solution='',
                            score=0,
                        )
            # 清空Redis缓存：删除与考试相关的缓存
            for user in should_exam_users:
                if user:
                    cache_key = f"user_exam_{user.id}_{exam_id}"
                    caches["sms"].delete(cache_key)

            logger.info(f"Exam {exam.title} ended at {end_time}.")
    except ObjectDoesNotExist:
        logger.error(f"Exam {exam_id} does not exist.")
    except Exception as e:
        logger.error(f"An error occurred while ending exam {exam_id}: {e}.")

